#pragma once
#include <iostream>
#include <string>
#include <sys/types.h>
#include <sys/socket.h>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <unistd.h>
#include <cerrno>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <functional>
#include <signal.h>
#include "logMessage.hpp"
#include "Sock.hpp"
#include <fcntl.h>
#define gport 8080
#define default_sort -1
namespace select_ns
{
    using func = function<void(fd_set)>;
    static const int dnum = sizeof(fd_set)*8;

    class CalServer
    {
    public:
        CalServer(const uint16_t &port = gport) : _port(port), _listensort(-1)
        {
            for(int i = 0;i<dnum;i++)
            {
                _fdarray[i] = default_sort; 
            }
        }
        ~CalServer()
        {
        }
        void Print()
        {
            for(int i = 0;i<dnum;i++)
            {
                if(_fdarray[i] != default_sort)
                {
                    cout<<"fd list :"<<_fdarray[i]<<endl;
                }
            }
        }
        void HanderEvent(fd_set &rfds)
        {
            // accept
            if (FD_ISSET(_listensort, &rfds))
            {
                string client_ip ;
                uint16_t client_port;
                //accept得到的sock就是后续文件操作的“文件指针”
                int sock = Sock::Accept(_listensort,&client_ip,&client_port);
                logMessage(NORMAL,"accept sucess [%s][%d]",client_ip.c_str(),client_port);
                //把新得到的sock加入select让他帮我管理
                int i = 0;
                for(;i<dnum;i++)
                {
                    if(_fdarray[i] == default_sort)
                    break;
                }
                if(i == dnum)
                {
                    logMessage(WARING,"is full,you need to wait");
                    close(sock);
                }
                else
                _fdarray[i] = sock;
                Print();
            }
        }
        void Init()
        {
            _listensort = Sock::Socket();
            Sock::Bind(_listensort, _port);
            Sock::Listen(_listensort);
            _fdarray[0] = _listensort;
        }
        void start()
        {
            while (1)
            {
                fd_set rfds;
                // 将位图全部置为0
                FD_ZERO(&rfds);
                int maxfd = _fdarray[0];
                // 在位图中标记_listensort
                for(int i = 0;i<dnum;i++)
                {
                    if(_fdarray[i] != default_sort)
                    {
                        FD_SET(_fdarray[i], &rfds);
                    }
                    if(maxfd < _fdarray[i])
                    maxfd = _fdarray[i];
                }
                struct timeval timeout = {1, 0};
                // 非阻塞式io
                int n = select(_listensort + 1, &rfds, nullptr, nullptr, &timeout);
                switch (n)
                {
                case 0:
                    logMessage(NORMAL, "time out....");
                    break;
                case -1:
                    logMessage(WARING, "select err,errString :%s", strerror(errno));
                    break;
                default:
                    // 说明事件就绪了
                    logMessage(NORMAL, "get a new link..");
                    HanderEvent(rfds);
                    break;
                }
            }
        }

    private:
        int _port;
        int _listensort;
        int _fdarray[dnum];
    };
}